forecast <- function(x12,symbol){
library(xts)

extractLastYear <-function (timeSerie){
  as.POSIXlt(index(timeSerie[length(timeSerie)]))$year
}


raw_predict <-function(timeSerieOrg, 
                       timeSerieIndex,
                       forcastingFunction,
                       maxHistory=10000,
                       transformData=function(x) return(x),
                       detransformData=NA){
  
  timeSerie <- transformData(timeSerieOrg)
  lastYear <- extractLastYear(timeSerie)
  tsLength <-length(timeSerie)
  ret <- rep(0,tsLength)
  FirstUnknown<-0
  lastMoment<-1
  
  
  while( as.POSIXlt(index(timeSerie[lastMoment]))$year < lastYear ){
    lastMoment<-lastMoment+1
  }
  
  FirstUnknown<-lastMoment
  
  for (lastMoment in FirstUnknown:tsLength){
    firstMoment<-1
    if(lastMoment-maxHistory>1){
      firstMoment<-lastMoment-maxHistory
    }
    
    ret[lastMoment]<- forcastingFunction(
      timeSerie[firstMoment:(lastMoment-1)])
  }
  
  #print(ret)  
  detransformData(ret,timeSerieOrg,FirstUnknown,timeSerieIndex)
  
}

############################## TRANS FUNC


#simple detransform fuction withoutdiffs
simDeTrans <-function(predictedTS,originalSerie,firstPredicted,timeSerieIndex){
  tsLength<-length(originalSerie)
  xts(predictedTS[firstPredicted:tsLength], timeSerieIndex[firstPredicted:tsLength])
}

#transform diff function
diffTransform<-function(timeSeries){
  diff(timeSeries)[-1]
}

#detransform diff function
diffDeTransform<-function(predictedDiffs,originalSerie,firstPredicted,timeSerieIndex){
  tsLength<-length(originalSerie)
  predictedDiffs <- xts(predictedDiffs[firstPredicted:(tsLength-1)], timeSerieIndex[(firstPredicted+1):tsLength])
  
  predictedPartMinusPeriod <- originalSerie[(firstPredicted):length(originalSerie)] 
  return(lag(predictedPartMinusPeriod)+predictedDiffs)
}

#transform diff log function
logDiffTransform<-function(timeSeries){
  tmpTimeSeries = log(timeSeries)
  diffTransform(tmpTimeSeries)
}

#detransform diff log function (exp)
logDiffDeTransform<-function(predictedSerie,originalSerie,firstPredicted,timeSerieIndex){
  tsLength<-length(originalSerie)
  predictedSerie <- xts(predictedSerie[firstPredicted:(tsLength-1)], timeSerieIndex[(firstPredicted+1):tsLength])
  
  predictedPartMinusPeriod <- log(originalSerie[(firstPredicted):length(originalSerie)])
  return(exp(lag(predictedPartMinusPeriod)+predictedSerie))
}

#transform return log function
logReturnTransform<-function(timeSeries){
  tmpTimeSeries = xts(as.vector(timeSeries[2:length(timeSeries)])/as.vector(timeSeries[1:(length(timeSeries)-1)]),index(timeSeries[-1]))
  log(tmpTimeSeries)
}

#logReturnTransform(zf)
#log(as.vector(zf[2])/as.vector(zf[1]))

#detransform return log function (exp)
logReturnDeTransform<-function(predictedSerie,originalSerie,firstPredicted,timeSerieIndex){
  predictedSerie <- exp(predictedSerie)
  tsLength<-length(originalSerie)
  predictedSerie <- xts(predictedSerie[firstPredicted:(tsLength-1)], timeSerieIndex[(firstPredicted+1):tsLength])
  
  predictedPartMinusPeriod <- originalSerie[(firstPredicted):length(originalSerie)]
  return(lag(predictedPartMinusPeriod)*predictedSerie)
}

#transform log function
logTransform<-function(timeSeries){
  log(timeSeries)
}

#logTransform(zf)

#detransform log function (exp)
logDeTransform<-function(predictedSerie,originalSerie,firstPredicted,timeSerieIndex){
  tsLength<-length(originalSerie)
  predictedSerieTmp <- xts(predictedSerie[firstPredicted:(tsLength-1)], timeSerieIndex[(firstPredicted+1):tsLength])
  return(exp(predictedSerieTmp))
}


# autoregressive family
autoregresiveCreator <- function(maxOrder, type) {
  return(
    function(timeSerie){
      options(warn=-1)
      sim <- ar(x=timeSerie, order.max=maxOrder, method=type, demean=FALSE)
      options(warn=1)
      gc()
      return((predict(sim, n.ahead=1)$pred)[1])
    })
}

library(zoo)
library(xts)
#smooth the data 
smoothData <- function(timeSeries, MeanDepth, IndexTimeSeries) {
  ret <- as.vector(rollapply(timeSeries, MeanDepth, mean, align="right"))
  return(as.xts(ret,order.by=IndexTimeSeries[MeanDepth:length(IndexTimeSeries)]))
}

# plot(zf)
# plot(smoothData(zf,4,IndexZf))

# AR on smoothed data
ARSmoothedPredict <- function(maxAROrder, ARtype, MeanDepth) {
  return(
    function(timeSeries){
      smoothedTimeSeries = smoothData(timeSeries,MeanDepth,index(timeSeries))
      options(warn=-1)
      sim <- ar(x=smoothedTimeSeries, order.max=maxAROrder, method=ARtype, demean=FALSE)
      options(warn=1)
      gc()
      return((predict(sim, n.ahead=1)$pred)[1])
    })
}

MartingalePredict <- function(timeSeries){
  return(as.vector(timeSeries[length(timeSeries)]))
}

ownPredict <-function(timeSeries, 
                      forcastingFunction,
                      maxHistory=10000,
                      transformData=function(x) return(x),
                      detransformData=NA){
  
  predictedTimeSeries <- raw_predict(timeSeries, 
                                     index(timeSeries),
                                     forcastingFunction,
                                     maxHistory,
                                     transformData,
                                     detransformData) 
  
  lastYear <- extractLastYear(timeSeries)
  tsLength <-length(timeSeries)
  firstUnknown<-1
  
  while( as.POSIXlt(index(timeSeries[firstUnknown]))$year < lastYear ){
    firstUnknown<-firstUnknown+1
  }
  
  realTimeSeries <- timeSeries[firstUnknown:tsLength]
  aafe <- mean(abs(realTimeSeries-predictedTimeSeries))
  list(x2=realTimeSeries,y2=predictedTimeSeries,aafe=aafe)
}


if (symbol == 'USDEUR'){
  forecast <-ownPredict(x12, MartingalePredict, 1, function(x) return(x), simDeTrans)
}else if (symbol =='GOOG'){
  forecast <-ownPredict(x12, autoregresiveCreator(1,'ols'),250, logReturnTransform, logReturnDeTransform)
}else if (symbol=='ZF'){
  forecast <-ownPredict(x12, ARSmoothedPredict(2,'ols',2),250, diffTransform, diffDeTransform)
}else if (symbol =='CL'){
  forecast <-ownPredict(x12, autoregresiveCreator(6,'ols'),100, diffTransform, diffDeTransform)
}else{
  print('unknown symbol')
}
return(forecast)
}

fc <- forecast(euro,'USDEUR')
print(fc$aafe)
